package Tools;

import java.util.ArrayList;
import java.util.Random;


public class KMeans implements Clustering{
	
	private double quantError=0.1;
	
	@Override
	public ArrayList<int[]> cluster(Consensus cs, OpinionBase profile, String obj, int clusterCount) {
		
		int[][] centers=new int[clusterCount][4];
		int[][] oldCenters=new int[clusterCount][4];
		
		
		Graph g=new Graph();
		g.createGraph();
		Integer[] keys=new Integer[g.map.keySet().size()];
		int counts=0;
		for(Integer in:g.map.keySet()){
			keys[counts]=in;
			counts++;
		}
		
		Random rand=new Random();
		
		//Choose n initial centers
		for (int i = 0; i < centers.length; i++) {
			int toSplit=keys[rand.nextInt(keys.length)];
			int[] center=new int[4];
			center[3]=toSplit%10;
			toSplit/=10;
			center[2]=toSplit%10;
			toSplit/=10;
			center[1]=toSplit%10;
			toSplit/=10;
			center[0]=toSplit;
			
			centers[i]=center;
		}
		
		DistanceFun dst=new BotTopDistance();
		
		double checkSum=Double.MAX_VALUE;
		do{
			ArrayList<OpinionBase> clusters=new ArrayList<OpinionBase>();
			
			for(int i=0;i<centers.length;i++){
				clusters.add(new OpinionBase());
			}
			for(PolarRepresentation pr:profile.getObjectOpinions(obj)){
				double minDist=Double.MAX_VALUE;
				int bestCluster=-1;
				for(int i=0;i<centers.length;i++){
					double sum=0;
					for(InternalStatement b:pr.ir){	
						sum+=Math.pow(b.weight*dst.calculate(PolarRepresentation.toInterval(new InternalStatement(centers[i],1)),PolarRepresentation.toInterval(b)),2);
					}
					if(sum<minDist){
						minDist=sum;
						bestCluster=i;
					}
				}
				clusters.get(bestCluster).put(pr.aid, obj, pr);
			}
			
			for(int i=0;i<centers.length;i++){
				oldCenters[i]=centers[i];
				centers[i]=cs.refine(cs.calculate(obj, clusters.get(i)));
			}
			double checksum=0;
			
			DistanceFun dist = new BotTopDistance();
			
			double olddist=0;
			double dists= 0;
			
			double sum=0;
			int counter=0;
			for(int i=0;i<centers.length;i++){
				int[] a=centers[i];
				
				for(PolarRepresentation pr:clusters.get(i).getObjectOpinions(obj)){
					for(InternalStatement b:pr.ir){	
						sum+=Math.pow(b.weight*dist.calculate(PolarRepresentation.toInterval(new InternalStatement(a, 1)),PolarRepresentation.toInterval(b)),2);
					}
					counter++;
				}
			}
			dists=sum/counter;
			sum=0;
			counter=0;
			
			for(int i=0;i<oldCenters.length;i++){
				int[] a=oldCenters[i];
				for(PolarRepresentation pr:clusters.get(i).getObjectOpinions(obj)){
					for(InternalStatement b:pr.ir){	
						sum+=Math.pow(b.weight*dist.calculate(PolarRepresentation.toInterval(new InternalStatement(a, 1)),PolarRepresentation.toInterval(b)),2);
					}
					counter++;
				}
			}
			olddist=sum/counter;
			
			checkSum=(olddist-dists)/dists;
		}while(checkSum>quantError);
		
		ArrayList<int[]> ret=new ArrayList<int[]>();
		
		for(int[] cen:centers){
			ret.add(cen);
		}
		
		return ret;
	}

}
